package com.netease.nie.facade;

import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import com.netease.nie.base.cache.redis.Redis;
import com.netease.nie.base.cache.redis.RedisManager;
import com.netease.nie.base.cdn.CDNProperties;
import com.netease.nie.base.exceptions.BusinessException;
import com.netease.nie.base.machine.MachineConfig;
import com.netease.nie.base.utils.CopyUtils;
import com.netease.nie.base.utils.CustomDateFormatUtils;
import com.netease.nie.base.utils.DateUtils;
import com.netease.nie.config.CreditGradeProperties;
import com.netease.nie.constants.BusinessConstants;
import com.netease.nie.constants.CachePrefixConstants;
import com.netease.nie.constants.CreditHistoryChangeStants;
import com.netease.nie.constants.CreditHistoryOriginStants;
import com.netease.nie.constants.CustomGoodsConstants;
import com.netease.nie.constants.GoodsTypeStants;
import com.netease.nie.constants.OrdersStatusConstants;
import com.netease.nie.constants.OrdersTraceConstants;
import com.netease.nie.dto.DrawLotteryActivityDetailDto;
import com.netease.nie.dto.DrawLotteryActivityDto;
//import com.netease.nie.dto.DrawLotteryCreditGoodsInfoDto;
import com.netease.nie.dto.DrawLotteryNormalGoodsInfoDto;
import com.netease.nie.dto.DrawLotteryResultDto;
import com.netease.nie.dto.GoodsInfoDto;
import com.netease.nie.model.Credit;
import com.netease.nie.model.CreditHistory;
//import com.netease.nie.dto.DrawLotteryPromptDto;
import com.netease.nie.model.DrawLotteryActivity;
import com.netease.nie.model.DrawLotteryCreditGoodsInfo;
import com.netease.nie.model.DrawLotteryNormalGoodsInfo;
import com.netease.nie.model.DrawLotteryParticipationRecord;
import com.netease.nie.model.DrawLotteryPrompt;
import com.netease.nie.model.Orders;
import com.netease.nie.model.OrdersTrace;
import com.netease.nie.model.User;
import com.netease.nie.service.CreditHistoryService;
import com.netease.nie.service.CreditService;
import com.netease.nie.service.DrawLotteryActivityService;
import com.netease.nie.service.DrawLotteryCreditGoodsInfoService;
import com.netease.nie.service.DrawLotteryNormalGoodsInfoService;
import com.netease.nie.service.DrawLotteryParticipationRecordService;
import com.netease.nie.service.DrawLotteryPromptService;
import com.netease.nie.service.ExchangeCodeService;
import com.netease.nie.service.GoodsInfoService;
import com.netease.nie.service.OrderService;
import com.netease.nie.service.OrdersTraceService;
import com.netease.nie.service.UserInfoService;

/**
 * 抽奖业务接口实现
 * @author gzlibingjie
 */
@Service
public class DrawLotteryFacadeImpl implements DrawLotteryFacade {
	
	@Autowired
	private DrawLotteryActivityService drawLotteryActivityService;
	
	@Autowired
	private DrawLotteryNormalGoodsInfoService drawLotteryNormalGoodsInfoService;
	
	@Autowired
	private DrawLotteryCreditGoodsInfoService drawLotteryCreditGoodsInfoService;
	
	@Autowired
	private DrawLotteryPromptService drawLotteryPromptService;
	
	@Autowired DrawLotteryParticipationRecordService drawLotteryParticipationRecordService;
	
	@Autowired
	private CreditService creditService;
	
	@Autowired
	private CreditHistoryService creditHistoryService;
	
	@Autowired
	private GoodsInfoService goodsInfoService;
	
	@Autowired
	private OrderService orderService;
	
	@Autowired
	private OrdersTraceService ordersTraceService;
	
	@Autowired
	private UserInfoService userInfoService;
	
	@Autowired
	private ExchangeCodeService exchangeCodeService;
	
	@Autowired
	private Redis redis;
	
	@Autowired
	private MachineConfig machineConfig;
	
	@Autowired
	private CreditGradeProperties creditGradeProperties;
	
	@Autowired
	private CDNProperties cdnProperties;
	
	private static final String EXCHANGE_CODE_LIST_PREFIX = CachePrefixConstants.GoodsPrefix.GOODS_EXCHANGE_CODE_LIST_PREFIX;
	
	private static final String GOODS_SERIAL_PREFIX = CachePrefixConstants.GoodsPrefix.GOODS_SERIAL_PREFIX;
	
	/**
	 * 获取抽奖活动列表
	 * @param pageIndex 当前页码
	 * @return 抽奖活动列表
	 */
	@Override
	@Transactional(readOnly = true)
	public List<DrawLotteryActivityDto> list(Integer pageIndex) {
		List<DrawLotteryActivity> drawLotteryActivityList = drawLotteryActivityService.list(pageIndex);
		return CopyUtils.copyOriginListToDestList(drawLotteryActivityList, DrawLotteryActivityDto.class);
	}

	/**
	 * 获取抽奖活动详情
	 * @param id 抽奖活动ID
	 * @return 抽奖活动详情
	 */
	@Override
	@Transactional(readOnly = true)
	public DrawLotteryActivityDetailDto get(Integer id) {
		DrawLotteryActivityDetailDto drawLotteryActivityDetailDto = new DrawLotteryActivityDetailDto();
		DrawLotteryActivity drawLotteryActivity = drawLotteryActivityService.queryById(id);
		if (drawLotteryActivity == null) {
			throw new BusinessException(BusinessConstants.DRAW_LOTTERY_ACTIVITY_NOT_EXISTS.getCode(), "抽奖活动不存在");
		}
		CopyUtils.copy(drawLotteryActivityDetailDto, drawLotteryActivity);
		
		// 获取普通商品列表
		List<DrawLotteryNormalGoodsInfo> normalGoodsInfoList = drawLotteryNormalGoodsInfoService.listByActivityId(id);
		List<DrawLotteryNormalGoodsInfoDto> normalGoodsInfoDtoList = CopyUtils.copyOriginListToDestList(normalGoodsInfoList, DrawLotteryNormalGoodsInfoDto.class);
		for (int i = 0; i < normalGoodsInfoDtoList.size(); i++) {
			DrawLotteryNormalGoodsInfoDto normalGoodsInfoDto = normalGoodsInfoDtoList.get(i);
			normalGoodsInfoDto.setThumbnailUrl(cdnProperties.getCdnPrefix() + normalGoodsInfoList.get(i).getThumbnailWapUrl());
		}
		drawLotteryActivityDetailDto.setNormalGoodsInfoList(normalGoodsInfoDtoList);
		
		/**
		// 获取积分商品列表
		List<DrawLotteryCreditGoodsInfo> creditGoodsInfoList = drawLotteryCreditGoodsInfoService.listByActivityId(id);
		List<DrawLotteryCreditGoodsInfoDto> creditGoodsInfoDtoList = CopyUtils.copyOriginListToDestList(creditGoodsInfoList, DrawLotteryCreditGoodsInfoDto.class);
		for (int i = 0; i < creditGoodsInfoDtoList.size(); i++) {
			DrawLotteryCreditGoodsInfoDto creditGoodsInfoDto = creditGoodsInfoDtoList.get(i);
			creditGoodsInfoDto.setThumbnailUrl(CommonConstants.PIC_PREFIX + creditGoodsInfoList.get(i).getThumbnailWapUrl());
		}
		drawLotteryActivityDetailDto.setCreditGoodsInfoList(creditGoodsInfoDtoList);
		
		// 获取不中奖提示列表
		List<DrawLotteryPrompt> promptList = drawLotteryPromptService.listByActivityId(id);
		List<DrawLotteryPromptDto> promptDtoList = CopyUtils.copyOriginListToDestList(promptList, DrawLotteryPromptDto.class);
		for (int i = 0; i < promptDtoList.size(); i++) {
			DrawLotteryPromptDto promptDto = promptDtoList.get(i);
			promptDto.setThumbnailUrl(CommonConstants.PIC_PREFIX + promptList.get(i).getThumbnailWapUrl());
		}
		drawLotteryActivityDetailDto.setPromptList(promptDtoList);
		*/
		
		return drawLotteryActivityDetailDto;
	}

	/**
	 * 进行抽奖
	 * @param id 抽奖活动ID
	 * @return 抽奖结果
	 */
	@Override
	@Transactional(rollbackFor = Exception.class, isolation = Isolation.SERIALIZABLE)
	public DrawLotteryResultDto draw(Integer id, Long userId) {
		// 更新参与次数
		// 注意：为避免死锁，此处第一步必须先做写操作！不能先读！
		drawLotteryActivityService.addDrawUserPt(id);
		
		if (userId == null) {
			throw new BusinessException(BusinessConstants.USER_NOT_LOGIN.getCode(), "用户未登录");
		}
		DrawLotteryResultDto drawLotteryResultDto = new DrawLotteryResultDto();
		
		DrawLotteryActivity drawLotteryActivity = drawLotteryActivityService.queryById(id);
		if (drawLotteryActivity == null) {
			throw new BusinessException(BusinessConstants.DRAW_LOTTERY_ACTIVITY_NOT_EXISTS.getCode(), "抽奖活动不存在");
		} else if (drawLotteryActivity.getPutOnStatus() == 0) {
			throw new BusinessException(BusinessConstants.DRAW_LOTTERY_NOT_AVAILABLE.getCode(), "当前抽奖暂不可用，请稍后再试");
		}
		int price = drawLotteryActivity.getPrice();
		Integer prizeId = null;
		
		// 检查积分是否够用
		Credit credit = creditService.queryUserCreditByUserId(userId);
		if (credit.getCurrentCredit() < price) {
			throw new BusinessException(BusinessConstants.CREDIT_NOT_ENOUGH.getCode(), "您的奇遇点不足");
		}
		
		// 记录积分历史
		long currentTimeMills = DateUtils.currentTimeInMills();
		int generateDate = CustomDateFormatUtils.getyyyyMMddInt(currentTimeMills);
		CreditHistory creditHistory = new CreditHistory();
		creditHistory.setChangeOriginStatus(CreditHistoryOriginStants.DRAW_LOTTERY.getCode());
		creditHistory.setChangeStatus(CreditHistoryChangeStants.DECR.getCode());
		creditHistory.setCreateTime(currentTimeMills);
		creditHistory.setCredit(price);
		creditHistory.setUserId(userId);
		creditHistory.setGenerateDate(generateDate);
		creditHistory.setChangeOriginDesc("参与抽奖");
		creditHistoryService.insertCreditHistory(creditHistory);
		
		int drawCredit = 0;
		
		// 尝试抽普通奖品
		DrawLotteryNormalGoodsInfo drawLotteryNormalGoodsInfo = drawLotteryNormalGoodsInfoService.draw(id);
		if (drawLotteryNormalGoodsInfo != null) {    // 抽中普通奖品
			prizeId = drawLotteryNormalGoodsInfo.getId();
			
			// 更新中奖次数
			drawLotteryActivityService.addPrizeTimes(id);
			
			// 生成订单
			Orders order = new Orders();
			order.setUserId(userId);
			order.setGoodsId(drawLotteryNormalGoodsInfo.getGoodsId());
			order.setCustomGoodsCode(CustomGoodsConstants.DRAW_LOTTERY.getCode());
			order.setCustomGoodsId(drawLotteryNormalGoodsInfo.getId());
			order.setGoodsTitle(drawLotteryNormalGoodsInfo.getTitle());
			GoodsInfoDto goods = goodsInfoService.queryGoodsInfoById(drawLotteryNormalGoodsInfo.getGoodsId());
			order.setCategoryId(goods.getCategoryId());
			order.setGoodsType(goods.getGoodsType());
			order.setStatus(OrdersStatusConstants.GET_GOODS.getCode());
			if (goods.getGoodsType() == GoodsTypeStants.REDEEM_CODE.getCode()) {
				String key = EXCHANGE_CODE_LIST_PREFIX + goods.getId();
				if (redis.exists(key)) {
					String exchangeCodeStr = redis.lpop(key);
					if (StringUtils.isBlank(exchangeCodeStr)) {
						throw new BusinessException(BusinessConstants.EXCHANGE_CODE_NOT_EXISTS.getCode(), "商品兑换码不存在");
					}
					order.setExchangeCodeId(Integer.valueOf(exchangeCodeStr));
				} else {
					throw new BusinessException(BusinessConstants.EXCHANGE_CODE_NOT_EXISTS.getCode(), "商品兑换码不存在");
				}
			}
			order.setPrice(price);
			order.setGenerateDate(generateDate);
			order.setSerialNumber(computeGoodsSerialNumber(goods.getId(), currentTimeMills));
			order.setCreateTime(currentTimeMills);
			orderService.insertOrder(order);
			
			if (goods.getGoodsType() == GoodsTypeStants.ENTITY.getCode()) {
				OrdersTrace ordersTrace = new OrdersTrace();
				CopyUtils.copy(ordersTrace, order);
				ordersTrace.setOrderId(order.getId());
				ordersTrace.setStatus(OrdersTraceConstants.GOT_GOODS.getCode());
				ordersTraceService.insertOrdersTrace(ordersTrace);
			} else if (goods.getGoodsType() == GoodsTypeStants.REDEEM_CODE.getCode()) {
				exchangeCodeService.registerExchangeCodeOwner(order.getExchangeCodeId(), userId, currentTimeMills, order.getCustomGoodsCode(), order.getCustomGoodsId());
			}
			
			drawLotteryResultDto.setStatus(1);
			drawLotteryResultDto.setTitle(drawLotteryNormalGoodsInfo.getTitle());
			drawLotteryResultDto.setThumbnailUrl(cdnProperties.getCdnPrefix() + drawLotteryNormalGoodsInfo.getThumbnailWapUrl());
			drawLotteryResultDto.setOrderId(order.getId());
		} else {    // 尝试抽积分奖品
			DrawLotteryCreditGoodsInfo drawLotteryCreditGoodsInfo = drawLotteryCreditGoodsInfoService.draw(id);
			if (drawLotteryCreditGoodsInfo == null && drawLotteryActivity.getIsProtected() != null && drawLotteryActivity.getIsProtected().intValue() == 1) {    // 开启了次数保护
				int minimumTimes = drawLotteryActivity.getMinimumTimes();
				List<DrawLotteryParticipationRecord> recordList = drawLotteryParticipationRecordService.queryLast(userId, drawLotteryActivity.getId(), minimumTimes);
				if (recordList.size() >= minimumTimes) {
					boolean needProtect = true;
					for (DrawLotteryParticipationRecord record : recordList) {
						if (record.getPrizeCode().intValue() != 0) {
							needProtect = false;
						}
					}
					if (needProtect) {    // 达到保底次数
						drawLotteryCreditGoodsInfo = drawLotteryCreditGoodsInfoService.queryMinByActivityId(drawLotteryActivity.getId());
					}
				}
			}
			if (drawLotteryCreditGoodsInfo != null) {    // 抽中积分奖品
				// 维护积分历史
				currentTimeMills = DateUtils.currentTimeInMills();
				CreditHistory drawCreditHistory = new CreditHistory();
				drawCreditHistory.setChangeOriginStatus(CreditHistoryOriginStants.DRAW_LOTTERY.getCode());
				drawCreditHistory.setChangeStatus(CreditHistoryChangeStants.INCR.getCode());
				drawCreditHistory.setCreateTime(currentTimeMills);
				drawCreditHistory.setCredit(drawLotteryCreditGoodsInfo.getCredit());
				drawCreditHistory.setUserId(userId);
				drawCreditHistory.setGenerateDate(generateDate);
				drawCreditHistory.setChangeOriginDesc("抽奖中奖");
				creditHistoryService.insertCreditHistory(drawCreditHistory);
				
				drawCredit = drawLotteryCreditGoodsInfo.getCredit();
				
				prizeId = drawLotteryCreditGoodsInfo.getId();
				
				drawLotteryResultDto.setStatus(2);
				drawLotteryResultDto.setTitle(drawLotteryCreditGoodsInfo.getTitle());
				drawLotteryResultDto.setThumbnailUrl(cdnProperties.getCdnPrefix() + drawLotteryCreditGoodsInfo.getThumbnailWapUrl());
			} else {    // 返回不中奖提示
				DrawLotteryPrompt drawLotteryPrompt = drawLotteryPromptService.randomQueryOne(id);
				if (drawLotteryPrompt == null) {
					throw new BusinessException(BusinessConstants.PROMPT_NOT_EXISTS.getCode(), "当前抽奖活动未配置不中奖提示");
				}
				drawLotteryResultDto.setStatus(0);
				drawLotteryResultDto.setTitle(drawLotteryPrompt.getPrompt());
				drawLotteryResultDto.setThumbnailUrl(cdnProperties.getCdnPrefix() + drawLotteryPrompt.getThumbnailWapUrl());
			}
		}
		
		// 从数据库扣除和发放积分
		int level = creditGradeProperties.getLevel(credit.getLastYearHighestCredit() + drawCredit);
		credit.setLevel(level);
		credit.setCurrentCredit(price - drawCredit);
		credit.setReadyToExpireCredit(price);
		credit.setTotalUseCredit(price);
		credit.setLastYearHighestCredit(drawCredit);
		credit.setTotalGainCredit(drawCredit);
		credit.setMaintainCredit(drawCredit);
		creditService.deductAndAddUserCredit(credit);
		
		// 保存抽奖记录
		DrawLotteryParticipationRecord drawLotteryParticipationRecord = new DrawLotteryParticipationRecord();
		drawLotteryParticipationRecord.setUserId(userId);
		User user = userInfoService.queryUserByUserId(userId);
		drawLotteryParticipationRecord.setUserNickname(user.getNickName());
		drawLotteryParticipationRecord.setDrawLotteryActivityId(id);
		drawLotteryParticipationRecord.setPrizeCode(drawLotteryResultDto.getStatus());
		drawLotteryParticipationRecord.setPrizeId(prizeId);
		drawLotteryParticipationRecord.setCreateTime(currentTimeMills);
		drawLotteryParticipationRecordService.insert(drawLotteryParticipationRecord);
		
		// 刷新积分缓存
		creditService.reloadUserCredit(userId);
		
		return drawLotteryResultDto;
	}
	
	/**
	 * 计算商品订单序列号
	 * @param goodsId 抽象商品id
	 * @param currentTime 当前时间
	 * @return 序列号
	 */
	private String computeGoodsSerialNumber(int goodsId, long currentTime) {
		String uniqueNumberKey = GOODS_SERIAL_PREFIX + goodsId;
		RedisManager redisManager = new RedisManager();
		int uniqueNumber = redisManager.incr(uniqueNumberKey);
		StringBuilder goodsSerialNumber = new StringBuilder();
		String yyyyMMddHHmmssSSSValue = String.valueOf(CustomDateFormatUtils.getyyyyMMddHHmmssSSSLong(currentTime));
		goodsSerialNumber.append(yyyyMMddHHmmssSSSValue);
		String machineNumber = machineConfig.getMachineNumber();
		goodsSerialNumber.append(machineNumber);
		String goodsIdStr = String.valueOf(goodsId);
		int goodsIdLen = goodsIdStr.length();
		if (goodsIdLen < 6) {
			int diff = 6 - goodsIdLen;
			for (int i = 0; i < diff; i++) {
				goodsIdStr = "0" + goodsIdStr;
			}
		}
		goodsSerialNumber.append(goodsIdStr);
		goodsSerialNumber.append(uniqueNumber);
		return goodsSerialNumber.toString();
	}

}
